/* enum */
import StorageModuleEnum from '@model/enum/StorageModuleEnum'
/* util */
import * as localForage from 'localforage'
import { getRootWindow } from '@src/util/dom'
import Log from '@src/util/log.ts'
import { isNull } from '@src/util/type'
import { setServerCach, getServerCach } from '@src/util/serverCach'


export type StorageSetType  = (
  Array<any> 
  | ArrayBuffer 
  | Blob 
  | Float32Array 
  | Float64Array 
  | Int8Array 
  | Int16Array 
  | Int32Array 
  | Number 
  | Object 
  | Uint8Array 
  | Uint16Array 
  | Uint32Array 
  | Uint8ClampedArray 
  | String
)

localForage.config({
  name: 'shb-pc-fe'
})

/** 
 * @description 获取用户id
*/
export function getUserId(): string | null {  
  try {
    const RootWindow: any = getRootWindow(window)
    const RootWindowInitData = JSON.parse(RootWindow?._init || '{}')
    
    return RootWindowInitData?.user?.userId || null
  } catch (error) {
    Log.error(error, getUserId.name)
    return null
  }
}

/** 
 * @description 获取存储key
*/
function getStorageKey(key: string): string {
  const userId: string | null = getUserId()
  return userId ? `${userId}-${key}` : key
}

export async function storageGet<T, K>(key: string, defaultValue: K, module?: StorageModuleEnum, serverCache = true, use24HoursCache = true): Promise<T | K | string | null> {  
  try {
    localForage.config({
      storeName: module
    })
    
    let storageKey = getStorageKey(key)

    // 从服务器获取缓存
    let value: T | K | string | null = serverCache ? await getServerCach(key, defaultValue, module, storageKey, use24HoursCache) : null
    if(!isNull(value)) return value

    // 如果 key 不存在，getItem() 将返回 null
    value = await localForage.getItem(storageKey)
    if (!isNull(value))  return value

    value = (
      localStorage.getItem(`${module}-${storageKey}`) 
      || localStorage.getItem(storageKey)
      || localStorage.getItem(key)
      || defaultValue
    )
    return value
  } catch (error) {
    console.error(`storageGet -> error ${error}`)
    return defaultValue
  }
}

/** 
 * @description 设置存储
 *  注意此方法是异步执行的
*/
export async function storageSet(key: string, value: StorageSetType, module: StorageModuleEnum, serverCache = true): Promise<any> {
  if(!key) return (
    Log.warn('Caused: can not set storage, because there is no key', storageSet.name)
  )
  
  localForage.config({
    storeName: module
  })
  
  const storageKey = getStorageKey(key)
  // Log.info(storageKey, 'storageKey', storageSet.name)
  
  try {
    const data = await localForage.setItem(storageKey, value)
    Log.info(data, 'data', 'localForage.setItem')
  } catch (error) {
    localStorage.setItem(`${module}-${storageKey}`, JSON.stringify(value))
    console.error('storageSet -> error', error)
  }
  
  // 存入服务器
  serverCache && await setServerCach(key, value, module, storageKey)
}


export async function storageRm (module: StorageModuleEnum, moduleUniqueKey: string) {
  try {
    const storageKeys = await localForage.keys()
    storageKeys.forEach(key=> {
      if(key.includes(moduleUniqueKey)) {
        localForage.removeItem(key)
      }
    })
  } catch(err) {
    for (let i = 0; i < localStorage.length; i++) {
      const key = localStorage.key(localStorage[i]) 
      if(key && key.includes(moduleUniqueKey)) {
        localStorage.removeItem(key)
      }
    }
    console.error('storageSet -> error', err)
    // localStorage.removeItem(`${module}-${storageKey}`, JSON.stringify(value))
    // console.error('storageSet -> error', error)
  }
}

export default {
  storageGet,
  storageSet,
  storageRm
}